﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.Utilities;
using ZealandIT.MsBuildTasks.Common;

namespace ZealandIT.MsBuildTasks
{
    /// <summary>
    /// Abstract base class for MSBuild tasks that require programmatic impersonation.
    /// Uses ImpersonationHelper in ZealandIT Common library. Which in turn uses low level LogonUserA Win32 API.
    /// </summary>
    public abstract class BaseImpersonationTask : Task
    {
        private string _fullusername;
        private string _password;

        /// <summary>
        /// Username of user to impersonate. To specify a domain user, use DOMAIN\User syntax.
        /// </summary>
        public string FullUsername
        {
            get { return _fullusername; }
            set { _fullusername = value; }
        }

        /// <summary>
        /// Property getter which extracts just the username from <see cref="FullUsername"/>, for when domain
        /// has been specified as part of FullUsername.
        /// </summary>
        protected string Username
        {
            get
            {
                if (_fullusername != null)
                {
                    int idx = _fullusername.IndexOf('\\');
                    if (idx != -1)
                    {
                        return _fullusername.Substring(idx + 1);
                    }
                    else
                        return _fullusername;
                }
                else
                    return _fullusername;
            }
        }

        /// <summary>
        /// Password for the user to impersonate.
        /// </summary>
        public string Password
        {
            get { return _password; }
            set { _password = value; }
        }

        /// <summary>
        /// Property getter that extracts the domain name from the <see cref="FullUsername"/>.
        /// </summary>
        protected string Domain
        {
            get
            {
                if (_fullusername != null)
                {
                    int idx = _fullusername.IndexOf('\\');
                    if (idx != -1)
                    {
                        return _fullusername.Substring(0, idx);
                    }
                    else
                        return null;
                }
                else
                    return null;
            }
        }

        /// <summary>
        /// Implementation of Execute in the base class. Takes care of wrapping
        /// the impersonation logic around the chunk of work to be done in its 
        /// inherited tasks.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            bool useImpersonation = (_fullusername != null && _password != null);
            if (useImpersonation)
            {
                ImpersonationHelper imp = new ImpersonationHelper();
                if (imp.ImpersonateValidUser(Username, Domain, Password))
                {
                    bool ret = this.ExecuteInternal();
                    imp.UndoImpersonation();
                    return ret;
                }
                else
                {
                    throw new Exception("Impersonation failed.");
                }
            }
            else
            {
                return this.ExecuteInternal();
            }
        }

        /// <summary>
        /// In derived classes, this task really does the main work.
        /// The Execute() method merely wraps the impersonation logic and
        /// calls this ExecuteInternal method.
        /// </summary>
        /// <returns></returns>
        protected abstract bool ExecuteInternal();
    }
}
